package edu.kpi.pzks2.simulator.links;

import edu.kpi.pzks2.simulator.processing.Processor;
import edu.kpi.pzks2.simulator.results.ChannelHistoryBean;
import edu.kpi.pzks2.simulator.results.TimeLine;

/**
 * Channel between to processors. Channel and SimplexChannel are used correspondingly to this scheme:
 * <pre>Processor:procA -> SimlexChannel:fromAtoB <-> Channel <-> SimplexChannel:fromBtoA <- Processor:procB</pre>
 *
 * @author Pustovit Michael, pustovitm@gmail.com
 */
public class Channel {
    public static final int DUPLEX_BRAKING = 2;

    private final Processor procA;
    private final Processor procB;

    private final SimplexChannel fromAtoB;
    private final SimplexChannel fromBtoA;

    private final int linkSpeed;
    private final boolean isDuplex;

    private final TimeLine history;

    public Channel(
            final Processor procA,
            final Processor procB,
            final int linkSpeed,
            final boolean isDuplex, 
            final boolean isPackageModeOn) {
        this.procA = procA;
        this.procB = procB;
        this.linkSpeed = linkSpeed * DUPLEX_BRAKING;
        this.isDuplex = isDuplex;
        this.history = new TimeLine(procA.getProcId() + "-" + procB.getProcId());

        fromAtoB = new SimplexChannel(this, procB, procA, isPackageModeOn);
        fromBtoA = new SimplexChannel(this, procA, procB, isPackageModeOn);
    }

    public SimplexChannel getChannel(final Processor proc) {
        if (proc == procA) {
            return fromAtoB;
        }

        if (proc == procB) {
            return fromBtoA; 
        }

        return null;
    }

    public void makeStep() {
        final int speed = (isDuplex) ? (linkSpeed / DUPLEX_BRAKING) : linkSpeed;

        if (isAnyBusyNow()) {
            history.addBean(new ChannelHistoryBean(fromAtoB, fromBtoA, procA, procB));
        } else {
            history.addBean(null);
        }

        fromAtoB.makeStep(speed);
        fromBtoA.makeStep(speed);
    }

    public TimeLine getHistory() {
        return history;
    }

    boolean isAnyBusyNow() {
        return fromAtoB.isTransmittingNow() || fromBtoA.isTransmittingNow();
    }
    
    public boolean isDuplex() {
        return isDuplex;
    }
    
    @Override
    public String toString() {
        return procA.getProcId() + "-" + procB.getProcId() 
                + (fromAtoB.isBusy() ? " (" + fromAtoB + ") " : " ") 
                + (fromBtoA.isBusy() ? " (" + fromBtoA + ")" : "");
    }
}